package tool

import cats.data.Validated
import implicits.Implicits._
import org.apache.commons.lang3.StringUtils

/**
 * Created by Administrator on 2019/12/20
 */
class FileValidTool(lines: List[List[String]]) {

  val headers = lines.head
  val hasHeaders = List("Age", "Leu", "Ile", "Val", "Phe", "Tyr","FBG","HbA1c", "SampleID")
  val fileInfo = "文件"

  def validHeadersRepeat = {
    val repeatHeaders = headers.diff(headers.distinct)
    val valid = repeatHeaders.isEmpty
    Validated.cond(valid, true, s"文件表头 ${repeatHeaders.head} 重复!")
  }

  def validHeadersHas = {
    val valid = StringUtils.isBlank(lines.head.mkString("\t"))
    Validated.cond(!valid, true, s"首行数据（表头）缺失!")
  }

  def validHeadersExist = {
    val noExistHeaders = hasHeaders.diff(headers)
    val valid = noExistHeaders.isEmpty
    Validated.cond(valid, true, s"文件表头 ${noExistHeaders.head} 不存在!")
  }

  def validAgeColumn = {
    val header = "Age"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isInt || column.toInt > 100 || column.toInt < 18
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为18-100之间的整数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validLeuColumn = {
    val header = "Leu"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validIleColumn = {
    val header = "Ile"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validValColumn = {
    val header = "Val"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validPheColumn = {
    val header = "Phe"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validTyrColumn = {
    val header = "Tyr"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validFbpColumn = {
    val header = "FBG"
    val min=0
    val max=100
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > max || column.toDouble < min
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为${min}-${max}之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validHba1cColumn = {
    val header = "HbA1c"
    val min=0
    val max=100
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > max || column.toDouble < min
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为${min}-${max}之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validColumnNum = {
    val info = lines.drop(1).zipWithIndex.map { case (tmpColumns, i) =>
      val columns = tmpColumns
      val inValid = columns.size <= headers.size
      val inMessage = if (!inValid) {
        s"文件第${i + 2}行列数不正确,存在多余列!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2).notEmptyLines
    Validated.cond(valid, true, messages.head)
  }

  def validNonEmpty = {
    val info = lines.drop(1).zipWithIndex.map { case (columns, i) =>
      val lineMap = headers.zip(columns).toMap
      val op = lineMap.filter { case (header, value) =>
        hasHeaders.contains(header)
      }.values.toList.filter { column =>
        StringUtils.isEmpty(column)
      }.headOption
      val inMessage = if (op.nonEmpty) {
        val j = columns.indexOf(op.get)
        s"文件第${i + 2}行第${j + 1}列为空!"
      } else ""
      (op.isEmpty, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2).notEmptyLines
    Validated.cond(valid, true, messages.head)
  }

}

object FileValidTool {

  def valid(lines: List[List[String]]) = {
    val fileValidTool = new FileValidTool(lines)
    import fileValidTool._
    validHeadersHas.andThen { b =>
      validHeadersRepeat
    }.andThen { b =>
      validHeadersExist
    }.andThen { b =>
      validColumnNum
    }.andThen { b =>
      validNonEmpty
    }.andThen { b =>
      validAgeColumn
    }.andThen { b =>
      validLeuColumn
    }.andThen { b =>
      validIleColumn
    }.andThen { b =>
      validValColumn
    }.andThen { b =>
      validPheColumn
    }.andThen { b =>
      validTyrColumn
    }.andThen { b =>
      validFbpColumn
    }.andThen { b =>
      validHba1cColumn
    }

  }

}
